package br.com.seuimovelnamao.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import br.com.seuimovelnamao.Util;
import br.com.seuimovelnamao.model.Bairro;
import br.com.seuimovelnamao.model.Cidade;
import br.com.seuimovelnamao.model.Endereco;
import br.com.seuimovelnamao.model.Estado;

public class LocalizacaoDAO extends MasterDAO {

	public LocalizacaoDAO(Session session) {
		super(session);
	}
	
	public Endereco getEndereco(Long id){
		Query query = this.getSession().createQuery("SELECT e FROM Endereco AS e WHERE e.id = :id");
		Endereco e = (Endereco)query.setParameter("id", id).uniqueResult();
		
		return e;
	}

	public Endereco getEnderecoPorCEP(String cep){
		
		Query query = this.getSession().createQuery("SELECT e FROM Endereco AS e WHERE e.cep = :cep");
		Endereco e = (Endereco)query.setParameter("cep", cep).uniqueResult();
		
		return e;
	}
	
	public List<Estado> getEstados(){
		return this.getSession().createCriteria(Estado.class).list();
	}
	
	public List<Cidade> getCidades(){
		return this.getSession().createCriteria(Cidade.class).list();
	}
	
	public List<Cidade> getCidadesPorEstado(Estado estado){
		
		Criteria criteria = session.createCriteria(Cidade.class);
		criteria.createAlias("estado", "estado");
		criteria.add(Restrictions.eq("estado", estado));
		return criteria.list();
	}
	
	public List<Bairro> getBairros(){
		return this.getSession().createCriteria(Bairro.class).list();
	}
	
	public List<Bairro> getBairrosPorCidade(Cidade cidade){
		
		Criteria criteria = this.getSession().createCriteria(Bairro.class);
		criteria.createAlias("cidade", "cidade");
		criteria.add(Restrictions.eq("cidade", cidade));
		return criteria.list();
	}

	public List<Estado> getDistinctEstados(){
		
		Query query = this.getSession().createQuery("SELECT distinct endereco.estado FROM Imovel");
		return query.list();
		
	}
	
	public List<Estado> getDistinctEstados(String categoria){
		
		String categoriaQuery = Util.getCategoriaQuery(categoria);
		
		Query query = this.getSession().createQuery("SELECT distinct endereco.estado FROM Imovel AS i " + categoriaQuery);
		if(!"".equals(categoriaQuery))
			query.setParameter("categoria", categoria);
		return query.list();
		
	}
	
	public List<Estado> getDistinctEstados(String categoria, String intencao){
		
		String categoriaQuery = Util.getCategoriaQuery(categoria);
		
		String sql = (categoriaQuery.equals("")) ? "WHERE" : categoriaQuery + " AND";
		
		Query query = this.getSession().createQuery("SELECT distinct endereco.estado FROM Imovel AS i " + sql + " i.intencao = :intencao");
		if(!"".equals(categoriaQuery))
			query.setParameter("categoria", categoria);
		query.setParameter("intencao", intencao);
		return query.list();
		
	}
	
	public List<Cidade> getDistinctCidades(Estado estado){
		
		Query query = this.getSession().createQuery("SELECT distinct i.endereco.cidade FROM Imovel AS i WHERE i.endereco.estado = :estado");
		return query.setParameter("estado", estado).list();
		
	}
	
	public List<Cidade> getDistinctCidades(String categoria, Estado estado){
		
		String categoriaQuery = Util.getCategoriaQuery(categoria);
		
		String sql = (categoriaQuery.equals("")) ? "WHERE" : categoriaQuery + " AND";
		
		Query query = this.getSession().createQuery("SELECT distinct i.endereco.cidade FROM Imovel AS i " + sql + " i.endereco.estado = :estado");
		if(!"".equals(categoriaQuery))
			query.setParameter("categoria", categoria);
		query.setParameter("estado", estado);
		return query.list();
		
	}
	
	public List<Cidade> getDistinctCidades(String categoria, String intencao, Estado estado){
		
		String categoriaQuery = Util.getCategoriaQuery(categoria);
		
		String sql = (categoriaQuery.equals("")) ? "WHERE" : categoriaQuery + " AND";
		
		Query query = this.getSession().createQuery("SELECT distinct i.endereco.cidade FROM Imovel AS i " + sql + " i.endereco.estado = :estado AND i.intencao = :intencao");
		if(!"".equals(categoriaQuery))
			query.setParameter("categoria", categoria);
		query.setParameter("intencao", intencao);
		query.setParameter("estado", estado);
		return query.list();
		
	}
	
	public List<Bairro> getDistinctBairros(String categoria, Cidade cidade){
		
		String categoriaQuery = Util.getCategoriaQuery(categoria);
		
		String sql = (categoriaQuery.equals("")) ? "WHERE" : categoriaQuery + " AND";
		
		Query query = this.getSession().createQuery("SELECT distinct i.endereco.bairro FROM Imovel AS i " + sql + " i.endereco.cidade = :cidade");
		if(!"".equals(categoriaQuery))
			query.setParameter("categoria", categoria);
		query.setParameter("cidade", cidade);
		return query.list();
		
	}
	
	public List<Bairro> getDistinctBairros(String categoria, String intencao, Cidade cidade){
		
		String categoriaQuery = Util.getCategoriaQuery(categoria);
		
		String sql = (categoriaQuery.equals("")) ? "WHERE" : categoriaQuery + " AND";
		
		Query query = this.getSession().createQuery("SELECT distinct i.endereco.bairro FROM Imovel AS i " + sql + " i.endereco.cidade = :cidade AND i.intencao = :intencao");
		if(!"".equals(categoriaQuery))
			query.setParameter("categoria", categoria);
		query.setParameter("intencao", intencao);
		query.setParameter("cidade", cidade);
		return query.list();
		
	}

	public Estado getEstadoPorUF(String uf){
		
		Criteria criteria = this.getSession().createCriteria(Estado.class);
		criteria.add(Restrictions.eq("uf", uf));
		return (Estado)criteria.uniqueResult();
	}
	
	public Cidade getCidadePorNomeURL(String nomeURL, Estado estado){
		
		Criteria criteria = session.createCriteria(Cidade.class);
		criteria.add(Restrictions.eq("nomeURL", nomeURL));
		criteria.createAlias("estado", "estado");
		criteria.add(Restrictions.eq("estado", estado));
		return (Cidade)criteria.uniqueResult();
	}
	
	public Bairro getBairroPorNomeURL(String nomeURL, Cidade cidade){
		
		Criteria criteria = session.createCriteria(Bairro.class);
		criteria.add(Restrictions.eq("nomeURL", nomeURL));
		criteria.createAlias("cidade", "cidade");
		criteria.add(Restrictions.eq("cidade", cidade));
		return (Bairro)criteria.uniqueResult();
	}
	
	public List<Estado> getEstadosPorLatLng(double northEastLat, double northEastLong, double southWestLat, double southWestLong, String status, String categoria, String intencao) {
		
		String categoriaIntencaoQuery = "";
		if(!"".equals(categoria))
			categoriaIntencaoQuery += " AND i.categoria = '"+categoria+"'";
		if(!"".equals(intencao))
			categoriaIntencaoQuery += " AND i.intencao = '"+intencao+"'";
		
		Query query = this.getSession().createQuery("SELECT e FROM Estado AS e, Imovel as i, ContratacaoPlano AS cp " +
				"WHERE e.lat BETWEEN :latMin AND :latMax" +
				" AND e.lng BETWEEN :lngMin AND :lngMax" +
				" AND (SELECT count(*) FROM Imovel AS i WHERE i.endereco.estado = e) > 0" +
				" AND i.endereco.estado = e" +
				" AND i.status = :status" +
				" AND cp.usuario = i.usuario" +
				" AND cp.pago = true" +
				" AND :data BETWEEN cp.inicio AND cp.fim" +
				categoriaIntencaoQuery);
		return query
				.setParameter("latMin", southWestLat)
				.setParameter("latMax", northEastLat)
				.setParameter("lngMin", southWestLong)
				.setParameter("lngMax", northEastLong)
				.setParameter("status", status)
				.setParameter("data", new Date())
				.list();
		
	}
	
	public List<Cidade> getCidadesPorLatLng(double northEastLat, double northEastLong, double southWestLat, double southWestLong, String status, String categoria, String intencao) {
		
		String categoriaIntencaoQuery = "";
		if(!"".equals(categoria))
			categoriaIntencaoQuery += " AND i.categoria = '"+categoria+"'";
		if(!"".equals(intencao))
			categoriaIntencaoQuery += " AND i.intencao = '"+intencao+"'";
		
		Query query = this.getSession().createQuery("SELECT c FROM Cidade AS c, Imovel as i, ContratacaoPlano AS cp " +
				"WHERE c.lat BETWEEN :latMin AND :latMax" +
				" AND c.lng BETWEEN :lngMin AND :lngMax" +
				" AND (SELECT count(*) FROM Imovel AS i WHERE i.endereco.cidade = c) > 0" +
				" AND i.endereco.cidade = c" +
				" AND i.status = :status" +
				" AND cp.usuario = i.usuario" +
				" AND cp.pago = true" +
				" AND :data BETWEEN cp.inicio AND cp.fim" +
				categoriaIntencaoQuery);
		return query
				.setParameter("latMin", southWestLat)
				.setParameter("latMax", northEastLat)
				.setParameter("lngMin", southWestLong)
				.setParameter("lngMax", northEastLong)
				.setParameter("status", status)
				.setParameter("data", new Date())
				.list();
		
	}
}